package com.example.springbootjavacode;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

import javax.tools.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author: wukangrong
 * @date: 2021/1/8 11:49
 * @description:
 */
@Component
public class ConcreteBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s*");


    private static final String BEAN_NAME = "twoServiceImpl";

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        StringBuilder code = new StringBuilder();

        String filePath = "E:\\importproject\\springboot-javacode\\src\\main\\resources\\javacode\\TwoServiceImpl.java";
        File codeFile = new File(filePath);
        if (codeFile.exists() &&  codeFile.isFile()) {
            try {
                FileInputStream codeStream = new FileInputStream(codeFile);
                BufferedReader codeReader = new BufferedReader(new InputStreamReader(codeStream));
                codeReader.readLine();
                String temp = codeReader.readLine();
                while (temp != null) {
                    code.append(temp).append("\n");
                    temp = codeReader.readLine();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("非有效文件路径：【" + filePath + "】");
        }
        System.out.println(code.toString());

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
        JavaFileManager javaFileManager = new JavaCodeTest.MyJavaFileManager(compiler.getStandardFileManager(collector, null, null));

        List<String> options = new ArrayList<>();
        options.add("-target");
        options.add("1.8");


        Matcher matcher = CLASS_PATTERN.matcher(code);
        String cls;
        if(matcher.find()){
            cls = matcher.group(1);
        } else{
            throw new IllegalArgumentException("No such class name in " + code);
        }

        JavaFileObject javaFileObject = new JavaCodeTest.MyJavaFileObject(cls, code.toString());
        Boolean result = compiler.getTask(null, javaFileManager, collector, options, null, Collections.singletonList(javaFileObject)).call();
        ClassLoader classloader = new JavaCodeTest.MyClassLoader();

        Class<?> clazz;
        try {
            clazz  = classloader.loadClass(cls);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(cls + " not load class");
        }
        if (Objects.isNull(clazz)) {
            throw new RuntimeException(cls + " is null");
        }
        System.out.println("类编译结果：" + result);
        BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(clazz).getBeanDefinition();
        registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}
